package com.fusion.core.comm.filetransfers;

import com.fusion.core.CoreSubsystem;
import com.fusion.core.file.blockstorage.BlockFile;
import com.fusion.core.file.blockstorage.BlockStorage;
import com.fusion.core.file.hash.Hash;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * @author SwethaShivakumar 
 * Project: fusion
 * Date: Mar 6, 2009
 * URL: http://fusionwiki.co.cc
 * Mail Me At: shiva@fusionproject.co.cc
 */
public class BlockStorageBlockProvider extends BlockProvider {
    private BlockFile bf;
    private boolean doneFilling;

    private CompleteFileBlockProvider wrapped;

    public BlockStorageBlockProvider(int blockNumber, Hash root, CoreSubsystem core) throws IOException {
        super(blockNumber, root, core);
        BlockStorage storage = core.getFileManager().getBlockStorageFor(root);
        bf = storage.getBlockFile(root);
        if(T.t)T.ass(bf != null, "Could not find block file when about to send block from block storage "+storage +", fd: "+fd);
    }

    public int fill(ByteBuffer buf) throws IOException {
        if (doneFilling) return -1;

        if (core.getFileManager().containsComplete(root)) {
            if(T.t)T.info("Hmm! We have this file complete now! Should not read from the block storage - this could re-open the file.");
            if (wrapped == null) {
                wrapped = new CompleteFileBlockProvider(blockNumber, root, core);
                wrapped.updateRead(read);
            }
            return wrapped.fill(buf);
        }

        int bs = prepare(buf);
        int n = bf.read(blockNumber, read, buf);
        read += n;

        if (n == -1 || read >= bs) {
            if(T.t)T.ass(read == bs, "read more then needed!");
            if(T.t)T.info("Block successfulyl provided. Rest is in buffer. Used block storage so we're not closing file.");
            //@todo: maybe should decide some way if we need to close the file channel - will probably leak open files..
            doneFilling = true;
        }
        return n;
    }
}
